package tech.aistar.pool;

import tech.aistar.util.JdbcUtil;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.LinkedList;

/**
 * 本类用来演示: 简易版本的连接池
 *
 * @author: success
 * @date: 2022/8/12 3:27 下午
 */
public class MyPool {//重量级的对象,创建和销毁的成本都是比较高. 设置成单例的.
    //1. 连接池的参数

    //初始值 - 连接池中预留3个可用的连接
    public int initSize=3;

    //连接池最大支持的连接的个数
    public int maxActive = 6;

    //定义一个变量,此时正在使用的连接的个数
    public int curr_count = 0;

    //维护的是连接对象,线程不安全
    public LinkedList<Connection> pools = new LinkedList<>();

    private static volatile MyPool instance = null;

    private MyPool(){
        //添加连接...连接的代理对象
        //Connection conn      =>  close();  //销毁连接
        //Connection connProxy =>  close();  //可以销毁,也可以放回到连接池中.
        for (int i = 0; i < initSize; i++) {
            pools.add(createConnection());
        }
    }

    public static MyPool getInstance(){
        if(instance == null){
            synchronized (MyPool.class){
                if(instance == null){
                    instance = new MyPool();
                }
            }
        }
        return instance;
    }

    public Connection getConnection(){//多线程调用
        synchronized (pools){
            if(pools.size()>0){//有可用的链接
                curr_count++;
                //直接从池子中取
                return pools.removeLast();
            }else if(curr_count<maxActive){
                System.out.println("===初始的连接已经用完了===");
                curr_count++;
                return createConnection();

            }else if(curr_count>maxActive){
                throw new RuntimeException("sorry,池子已经到达最大值了!");
            }
        }
        return null;
    }

    public Connection createConnection(){
        Connection conn = null;

        Connection proxy = null;
        try {
            //原始的接口
            conn = JdbcUtil.getConnection();

            //创建conn的代理对象
            Connection finalConn = conn;

            proxy = (Connection) Proxy.newProxyInstance(conn.getClass().getClassLoader(), conn.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    //prepareStatement close
                    Object obj = null;

                    if(method.getName().equals("close") && curr_count<=initSize){
                        System.out.println("==>.>");
                        //继续将该连接放入到连接池中去
                        pools.add(finalConn);
                        curr_count--;
                    }else if(method.getName().equals("close") && curr_count>initSize){
                        curr_count--;
                        finalConn.close();
                    } else{
                        obj = method.invoke(finalConn,args);//调用原始对象的核心方法
                    }
                    return obj;
                }
            });

        } catch (SQLException e) {
            e.printStackTrace();
        }

        return proxy;
    }

    public static void main(String[] args) throws SQLException {
        MyPool pool = MyPool.getInstance();
        Connection conn1 = pool.getConnection();
        Connection conn2 = pool.getConnection();
        Connection conn3 = pool.getConnection();
        System.out.println("正在使用的连接:"+pool.curr_count);
        System.out.println("连接池中剩余的连接:"+pool.pools.size());

        conn2.close();
        System.out.println("====");

        System.out.println("正在使用的连接:"+pool.curr_count);
        System.out.println("连接池中剩余的连接:"+pool.pools.size());
    }

}
